<?php

error_reporting ( E_ERROR | E_PARSE );

class Hoop_Memcache extends Memcache {
	
	private function _makeLockKey($key) {
		
		return $key . '$$lock';
	
	}
	
	public function get($keys) {
		
		if (! is_array ( $keys )) {
			
			$lkey = self::_makeLockKey ( $keys );
			
			$hmap = parent::get ( array (
					$keys,
					$lkey 
			) );
			
			if (! isset ( $hmap [$lkey] ) || $hmap [$lkey] === 'LOCK')
				
				return FALSE;
			
			return $hmap [$keys];
		
		} 

		else {
			
			$allkeys = $keys;
			
			foreach ( $keys as $key )
				
				$allkeys [] = self::_makeLockKey ( $key );
			
			$hmap = parent::get ( $allkeys );
			
			foreach ( $keys as $key ) {
				
				$lkey = self::_makeLockKey ( $key );
				
				if (! isset ( $hmap [$lkey] ) || $hmap [$lkey] === 'LOCK')
					
					$hmap [$key] = FALSE;
				
				unset ( $hmap [$lkey] );
			
			}
			
			return $hmap;
		
		}
	
	}
	
	public function getOrLock($keys) {
		
		if (! is_array ( $keys )) {
			
			$lkey = self::_makeLockKey ( $keys );
			
			$hmap = parent::get ( array (
					$keys,
					$lkey 
			) );
			
			if (! isset ( $hmap [$lkey] )) {
				
				parent::add ( $lkey, 'LOCK', 0, 15 );
				
				return FALSE;
			
			}
			
			return $hmap [$keys];
		
		} 

		else {
			
			$allkeys = $keys;
			
			foreach ( $keys as $key )
				
				$allkeys [] = self::_makeLockKey ( $key );
			
			$hmap = parent::get ( $allkeys );
			
			foreach ( $keys as $key ) {
				
				$lkey = self::_makeLockKey ( $key );
				
				if (! isset ( $hmap [$lkey] )) {
					
					parent::add ( $lkey, 'LOCK', 0, 15 );
					
					$hmap [$key] = FALSE;
				
				}
				
				unset ( $hmap [$lkey] );
			
			}
			
			return $hmap;
		
		}
	
	}
	
	public function set($key, $var, $flag = 0, $expire = 0) {
		
		if (parent::set ( $key, $var, $flag, (($expire > 0) ? ($expire + 600) : 0) )) {
			
			if (parent::set ( self::_makeLockKey ( $key ), (($expire > 0) ? (time () + $expire) : 0), 0, $expire ))
				
				return TRUE;
			
			else
				
				parent::delete ( $key );
		
		}
		
		return FALSE;
	
	}
	
	public function add($key, $var, $flag = 0, $expire = 0) {
		
		$lkey = self::_makeLockKey ( $key );
		
		$lock = parent::get ( $lkey );
		
		if ($lock !== FALSE) {
			
			return FALSE;
		
		}
		
		return self::set ( $key, $var, $flag, $expire );
	
	}
	
	public function replace($key, $var, $flag = 0, $expire = 0) {
		
		$lkey = self::_makeLockKey ( $key );
		
		$lock = parent::get ( $lkey );
		
		if ($lock === FALSE) {
			
			return FALSE;
		
		}
		
		return self::set ( $key, $var, $flag, $expire );
	
	}
	
	public function delete($key, $expire = 0) {
		
		$lkey = self::_makeLockKey ( $key );
		
		$lock = parent::get ( $lkey );
		
		if ($lock === FALSE || $lock === 'LOCK') {
			
			return FALSE;
		
		} 

		else if ($expire == 0) {
			
			return parent::delete ( $lkey );
		
		} 

		else {
			
			$etim = time () + $expire;
			
			if ($lock == 0 || $lock > $etim)
				
				return parent::set ( $lkey, $etim, 0, $expire );
			
			return TRUE;
		
		}
	
	}

}
